home *** CD-ROM | disk | FTP | other *** search
/ Developer CD Series 1994 November: Tool Chest / Dev.CD Nov 94.toast / Sample Code / Newton Sample Code 1.2 / Application Design / GoodForm-2 / GoodForm.text < prev    next >
Encoding:
Text File  |  1994-03-09  |  18.9 KB  |  673 lines  |  [TEXT/MPS ]

  1. // Copyright © 1993,4 Apple Computer, Inc. All rights reserved
  2. //Project Data for GoodForm
  3.  
  4. // application based constants
  5. constant kAppSymbol := '|GoodForm:PIEDTS|;
  6. constant kAppName := "GoodForm";
  7. constant kPackageName := "GoodForm:PIEDTS";
  8. constant kAppObject := '["Datum","Data"];
  9. constant kAppAll:= "All Data";
  10.  
  11. // soup based constants
  12. constant kSoupName := kPackageName;
  13. constant kSoupIndexes := '[];
  14.  
  15. // a default soup entry
  16. DefConst('kDefaultEntry, {text: "", labels: nil}); 
  17.  
  18.  
  19. // GetAppParams constants
  20. constant kMaxApplicationWidth:= 250;
  21. constant kMaxApplicationHeight:= 336;
  22.  
  23. // Install and RemoveScripts
  24.  
  25. InstallScript := func(partFrame)
  26. begin
  27.    // register support for routing
  28.     GetGlobals().routing.(kAppSymbol) := partFrame.theForm.entryRoutingFrame;
  29.     
  30.     // Register global find support
  31.     AddArraySlot(findApps, kAppSymbol);
  32.    
  33.     // register filing support
  34.     AddArraySlot(soupNotify, kSoupName);
  35.     AddArraySlot(soupNotify, kAppSymbol);
  36. end;
  37.  
  38.  
  39. RemoveScript := func(packageFrame)
  40. begin
  41.     // Unregister global find support
  42.     SetRemove(findApps, kAppSymbol);
  43.    
  44.     // un-register filing support
  45.     local soupNotifyPos:= ArrayPos(soupNotify, kAppSymbol, 0, nil);
  46.     ArrayRemoveCount(soupNotify, soupNotifyPos - 1, 2);
  47.     
  48.     // un-register routing support
  49.     RemoveSlot(GetGlobals().routing, kAppSymbol);
  50. end;
  51. // ---- End Project Data ----
  52.  
  53.  
  54. // ---- File GoodForm.t ----
  55.  
  56. // Before Script for "GoodFormBase"
  57. // Copyright © 1993,4 Apple Computer, Inc. All rights reserved
  58.  
  59. GoodFormBase :=
  60.    {
  61.     PutAway:
  62.       func(item)
  63.       // this might be called while we are not running, hense the 
  64.       // reason to check for the existance of uSoup.
  65.       begin
  66.           // get the entry from the system
  67.          local newEntry := item.body;
  68.          local theSoup := nil;
  69.       
  70.          // make sure we have the correct folder 
  71.          // for the labels slot
  72.          CheckThatFolderExists(newEntry);
  73.          if uSoup then
  74.             theSoup := uSoup
  75.          else 
  76.              theSoup := :RegisterCardSoup(kSoupName, kSoupIndexes, 
  77.                                     kAppSymbol, kAppObject);
  78.          
  79.          theSoup:AddToDefaultStore(newEntry);    // add the entry
  80.          
  81.          if not uSoup then
  82.             :UnRegisterCardSoup(kSoupName);    // clean up
  83.          
  84.          BroadcastSoupChange(kSoupName);    // tell everyone we've changed
  85.       end,
  86.     SetTarget:
  87.       func(entry)
  88.       // used by several of our methods, this function
  89.       // sets the target and adjusts both the cursor
  90.       // and the display appropriately
  91.       begin
  92.           if entry and cursor:Goto(entry) then
  93.               Target := entry
  94.           else
  95.               Target:= NIL;
  96.           
  97.           :UpdateFieldsFromEntry(target);
  98.       end,
  99.     viewSetupDoneScript:
  100.       func()
  101.       begin
  102.           // try to restore the old Target
  103.           local testTarget:= :GetLastTargetFromPrefsID();
  104.       
  105.           if testTarget and cursor:Goto(testTarget) then
  106.               :SetTarget(testTarget)
  107.           else
  108.               begin
  109.                   cursor:Reset();
  110.                   :SetTarget(cursor:Entry())
  111.               end;
  112.           
  113.           // add support for Newton Connection Kit
  114.           :AddNCKSupport();
  115.       end,
  116.     SaveToSoup:
  117.       func()
  118.       // Save Entry to Soup
  119.       begin
  120.           target.text := Clone(inputField.text);
  121.           EntryChange(target);
  122.           :SetDirty(nil);
  123.       end,
  124.     viewFormat: 524624,
  125.     viewQuitScript:
  126.       func()
  127.       // Remember to unregister the soup, and zap the currently used 
  128.       // references here, otherwise you get into trouble when removing
  129.       // the PCMCIA card with the app.
  130.       begin
  131.           // make sure we can restore the target if the card is removed
  132.           if Target then
  133.               prefsEntry:= EntryUniqueID(Target)
  134.           else
  135.               prefsEntry:= nil;
  136.           
  137.           // if the view is dirty, make sure the entry is changed
  138.           if dirty then
  139.               :SaveToSoup();
  140.       
  141.           // nil out all of our references and un-register the card soup
  142.           call kUnRegisterCardSoupFunc with (kSoupName);
  143.           uSoup:= nil;
  144.           cursor:= nil;
  145.           Target:= nil;
  146.       end,
  147.     AppAll: kAppAll,
  148.     target: nil,
  149.     FolderChanged:
  150.       func(soupname, oldLabel, newLabel)
  151.       // basic task is to assign new values to
  152.       // the 'labels slot in each check because
  153.       // the user has changed the name of one
  154.       // of the folders, NOTE this can be executed
  155.       // when this app is not running.
  156.       begin
  157.           local soup := GetUnionSoup(kSoupName);
  158.          if soup then 
  159.              begin
  160.                 local localCursor := query(soup, {type: 'index,
  161.                    validTest: func(entry)
  162.                                    begin
  163.                                       return entry.labels = oldLabel;
  164.                                    end
  165.                                        });
  166.       
  167.                 // change the labels of each entry in the soup to newLabel
  168.                 local localEntry := localCursor:Entry();
  169.                 while localEntry do 
  170.                     begin
  171.                        localEntry.labels := newLabel;
  172.                        EntryChange(localEntry);
  173.                        localEntry := localCursor:Next();
  174.                     end;
  175.                     
  176.                 // tell everyone else we've done it
  177.                   BroadcastSoupChange(kSoupName);
  178.              end;
  179.              
  180.          // redraw the folder tab if we are running
  181.          if folderTab then
  182.             folderTab:UpdateFilter(oldLabel, newLabel)
  183.       end,
  184.     viewFlags: 4,
  185.     UndoDuplicateEntry:
  186.       func(entry)
  187.       // use the delete message and the DeleteAnEntry method
  188.       // to crumple the view and remove the duplicate item
  189.       begin
  190.           inputField:Delete('DeleteAnEntry, [entry]);
  191.       end,
  192.     viewIdleScript:
  193.       func()
  194.       begin
  195.           if dirty then
  196.               :SaveToSoup();
  197.           return 5000;    // we will get called every 5 seconds
  198.       end,
  199.     AddNCKSupport:
  200.       func()
  201.       begin
  202.           // get a reference to the Directory soup and another
  203.           // reference to a cursor that points to our 
  204.           // metadata entry in the directory
  205.           local soup := GetStores()[0]:GetSoup("Directory");
  206.           local q := Query(Soup, 
  207.                                   {type: 'index,
  208.                                       validTest: func(item)
  209.                                           StrEqual(item.soup, kSoupName)}
  210.                                   );
  211.           
  212.           // if our metadata is not entered there, enter it
  213.           // should really test version of meta data                
  214.          if not q:Entry() then
  215.               begin
  216.                   local nckMeta := Clone(nckMetaData);
  217.                 soup:Add(nckMeta);
  218.               end
  219.       end,
  220.     DeleteActionScript:
  221.       func(entry, targetView)
  222.       begin
  223.           if Target then
  224.               begin
  225.                   inputField:Delete('DeleteAnEntry, [entry]);    // Delete does a crumple    
  226.                   AddUndoAction('undoDeleteEntry, [entry])
  227.               end
  228.           else
  229.               :Notify(kNotifyAlert, EnsureInternal(kAppName),
  230.                   EnsureInternal("There is no Data to delete"));
  231.       end,
  232.     viewBounds: {top: 20, left: -2, right: 231, bottom: 280},
  233.     appObject: kAppObject,
  234.     FilingChanged:
  235.       func()
  236.       // basic task, decide if the target should be displayed 
  237.       // using the current filter since the user has changed
  238.       // the way the entry is filed
  239.       begin
  240.           // make sure that the changes done to the labels slot
  241.           // are flushed from the cache
  242.           :SaveToSoup();
  243.           
  244.           if cursor:Goto(Target) then
  245.               begin
  246.                   // do nothing, leave display alone
  247.               end
  248.           else
  249.               begin
  250.                   cursor:Reset();
  251.                   :SetTarget(cursor:Entry());    // this displays the target
  252.               end
  253.       end,
  254.     cursor:
  255.       // keep track of the current cursor pointing at soup entries
  256.       nil,
  257.     FilterChanged:
  258.       func()
  259.       // basic task is to redraw the item(s) based 
  260.       // on the new filter selected by the user
  261.       begin
  262.           if Target and cursor:Goto(Target) then
  263.               begin
  264.                   // do nothing, leave display alone
  265.               end
  266.           else
  267.               begin
  268.                   // it must be filtered out, so display the first
  269.                   // non-filtered entry
  270.                   if dirty then
  271.                       :SaveToSoup();
  272.                   cursor:Reset();
  273.                   :SetTarget(cursor:Entry());    // this displays the target
  274.               end
  275.       end,
  276.     labelsFilter: nil,
  277.     ShowFoundItem:
  278.       func(entry, finder)
  279.       // shows the found item
  280.       begin
  281.          :SetTarget(entry);   // just go to the one selected, present it
  282.       end,
  283.     viewScrollDownScript:
  284.       func()
  285.       begin
  286.           // we use local variables in case the call to Next()
  287.           // fails, and we avoid restoring the cursor
  288.           local localCursor:= cursor:Clone();
  289.           local localEntry:= localCursor:Next();
  290.           if localEntry then
  291.               begin
  292.                   if dirty then
  293.                       :SaveToSoup();
  294.                   :SetTarget(localEntry);
  295.               end
  296.           else
  297.               GetRoot():SysBeep()
  298.       end,
  299.     viewOverviewScript:
  300.       func()
  301.       begin
  302.           :Notify(kNotifyAlert, EnsureInternal(kAppName),
  303.                       EnsureInternal("This application does not support an overview mode"));
  304.       end,
  305.     appSymbol: kAppSymbol,
  306.     viewJustify: 16,
  307.     nckMetaData:
  308.       {    // The metadata description is rich and powerful.  Please refer to
  309.           // the documentation for more details which are beyond the scope of 
  310.           // this simple example.
  311.           
  312.          soup: kSoupName,
  313.        
  314.          name: kAppName,
  315.        
  316.          version: 1,        // this code supports only version 1.0 of NCK
  317.                              // but 2.0 is backward compatible
  318.        
  319.          defaultDefinitions: {
  320.              textEntry: {label: "Text Entry:", size: 100},
  321.          },     
  322.        
  323.          displayInfo: [    // each entry here is a slot name in the textFrame
  324.                              // and the order here is the order they will appear
  325.                              // in NCK's DataBrowser Window.
  326.              'textEntry,
  327.          ],
  328.        
  329.          editInfo: [    // each entry here is a slot name in the textFrame
  330.                          // and the order here is the order they will appear
  331.                          // in NCK's Detail Window.
  332.              'textEntry,
  333.          ],
  334.        
  335.          exportInfo: [    // ???
  336.              'textEntry,
  337.          ],
  338.            
  339.            // The import() (from NCK to Newton) and the export() (from Newton
  340.            // to NCK) functions do the actual conversion of the data.  Note
  341.            // the structure of the textFrame used by NCK, it's easiest to
  342.            // see by looking in the export() function.  The "OriginalFrame"
  343.            // slot is actually storage for the soupFrame, and the other frames
  344.            // store conversions of those slots in the soupFrame to a textual
  345.            // format.
  346.            
  347.            import: func(textFrame)
  348.          // converts text frame to soup entry
  349.              begin
  350.                    if textFrame.originalFrame then
  351.                        textFrame.originalFrame.text:= "LIKE WOW MAN" // textFrame.textEntry
  352.                    else
  353.                        textFrame.originalFrame:= {text: "totally cool"};// textFrame.textEntry};
  354.                    
  355.                    textFrame.originalFrame    // this is the soupFrame!!!
  356.              end,
  357.        
  358.          export: func(soupFrame)
  359.          // converts soup entry to text frame for edit/display
  360.               begin
  361.                   local textFrame;
  362.                   textFrame:= {    originalFrame: soupFrame, 
  363.                                       textEntry: soupFrame.text};
  364.         
  365.                  textFrame;
  366.              end,
  367.       },
  368.     SetDirty:
  369.       func(IsDirty)
  370.       begin
  371.           dirty:= IsDirty;
  372.       end,
  373.     Find:
  374.       func(what, results, scope, statusForm)
  375.       begin
  376.          if statusForm then
  377.             statusForm:SetStatus("Searching in" && kAppName & $\u2026);
  378.       
  379.           // application can be closed when this call is made, so
  380.           // get a local cursor to the soup
  381.          local theSoup := GetUnionSoup(kSoupName);
  382.          if theSoup then
  383.              begin
  384.                 local theCursor := Query(theSoup, {type: 'text, text: what});
  385.       
  386.                 if theCursor:Entry() then 
  387.                     begin
  388.                        local theResult := 
  389.                        {
  390.                               _proto: GetRoot().soupFinder,
  391.                           owner: self,
  392.                           title: kAppName,
  393.                           findType: 'text,
  394.                           findWords: [what],
  395.                           cursor: theCursor,
  396.                        };
  397.                        AddArraySlot(results,theResult);
  398.                     end
  399.              end
  400.       end,
  401.     usoup: nil,
  402.     viewScrollUpScript:
  403.       func()
  404.       begin
  405.           // we use local variables in case the call to Prev()
  406.           // fails, and we avoid restoring the cursor
  407.           local localCursor:= cursor:Clone();
  408.           local localEntry:= localCursor:Prev();
  409.           if localEntry then
  410.               begin
  411.                   if dirty then
  412.                       :SaveToSoup();
  413.                   :SetTarget(localEntry);
  414.               end
  415.           else
  416.               GetRoot():SysBeep()
  417.       end,
  418.     DeleteAnEntry:
  419.       func(entry)
  420.       // remove the entry from our soup,
  421.       // adjust the target and the display
  422.       // note: all of our methods are built
  423.       // to handle a NIL Target
  424.       begin
  425.           EntryRemoveFromSoup(entry);
  426.           local newTarget:= cursor:Next();
  427.           if not newTarget then
  428.               newTarget:= cursor:Prev();
  429.           :SetTarget(newTarget);
  430.       end,
  431.     declareSelf: 'base,
  432.     viewSetupFormScript:
  433.       func()
  434.       begin
  435.           uSoup := call kRegisterCardSoupFunc with 
  436.               (kSoupName,kSoupIndexes,kAppSymbol,kAppObject);
  437.           cursor := Query(uSoup, {type: 'index, 
  438.                                           ValidTest: func(entry) begin 
  439.                                               return labelsFilter = '_all or 
  440.                                                   entry.labels = labelsFilter; end});
  441.           :SetupIdle(5000);
  442.           :ResizeToFitScreen();
  443.           TargetView:= self;
  444.       end,
  445.     DuplicateActionScript:
  446.       func(entryToDuplicate, targetView)
  447.       // copy the entry into our soup and
  448.       // adjust the target and display
  449.       begin
  450.           if entryToDuplicate then
  451.               begin
  452.                   local newEntry:= EntryCopy(entryToDuplicate, uSoup);
  453.                   :SetTarget(newEntry);
  454.                   AddUndoAction('UndoDuplicateEntry, [newEntry])
  455.               end
  456.           else
  457.               GetRoot():SysBeep();
  458.       end,
  459.     dirty: nil,
  460.     prefsEntry: nil,
  461.     SetupRoutingSlip:
  462.       func(fields)
  463.       // required to support routing, this function stuffs
  464.       // the slots of a frame passed to it by the system
  465.       begin
  466.           fields.title:= "Beamed GoodFormDatum:" && Target.text
  467.       end,
  468.     GetLastTargetFromPrefsID:
  469.       func()
  470.       // uses a soup query to get an entry using the old target's _uniqueID
  471.       begin
  472.           local localCursor := Query(uSoup, {
  473.                               type: 'index, 
  474.                               validTest: func(entry) 
  475.                                                   begin 
  476.                                                       return entry._uniqueID = prefsEntry;
  477.                                                   end});
  478.           return localCursor:Entry();
  479.       end,
  480.     viewclass: 74,
  481.     MakeNewEntry:
  482.       func()
  483.       // Create a new soup entry, the labels slot is used to support filing
  484.       begin
  485.             if dirty then
  486.               :SaveToSoup();
  487.           local newEntry := Clone(kDefaultEntry);
  488.           newEntry.labels := if labelsFilter = '_all then nil else labelsFilter ;
  489.             uSoup:AddToDefaultStore(newEntry);
  490.             newEntry;
  491.       end,
  492.     FindSoupExcerpt:
  493.       func(entry, finder)
  494.       begin
  495.           inherited:FindSoupExcerpt(entry, finder);   
  496.           // call inherited version
  497.       end,
  498.     UpdateFieldsFromEntry:
  499.       func(entry)
  500.       // Update the view field with the entry from the soup
  501.       // and if the entry is nil, display a notification
  502.       begin
  503.           if entry then
  504.               begin
  505.                   inputField:Show();
  506.                   itemLabel:Show();
  507.                   SetValue(inputField,'text, Clone(entry.text));
  508.                   SetValue(infoField, 'text, "Entry No:" && entry._uniqueID)
  509.               end
  510.           else
  511.               begin
  512.                   inputField:Hide();
  513.                   itemLabel:Hide();
  514.               // Should really differentiate between no entries in folder
  515.               //     and no entries at all (i.e., labelsFilter <> '_all and
  516.               //        no entries at all versus labelsFilter <> '_all and
  517.               //        entries in another folder
  518.                   SetValue(infoField,'text,
  519.                       if labelsFilter = '_all then
  520.                           "There is no Data to display."
  521.                       else
  522.                           "There is no Data in this folder");
  523.               end;
  524.           :SetDirty(nil);
  525.       end,
  526.     debug: "GoodFormBase",
  527.     undoDeleteEntry:
  528.       func(entry)
  529.       begin
  530.           uSoup:AddToDefaultStore(entry);
  531.           :SetTarget(entry);
  532.       end,
  533.     targetView: nil,
  534.     ResizeToFitScreen:
  535.       func()
  536.       // this function uses the global function, GetAppParams()
  537.       // to get the current size of the screen and adjusts our
  538.       // base view's size accordingly
  539.       begin
  540.           local params:= GetAppParams();  
  541.           self.viewBounds := RelBounds(
  542.               params.appAreaLeft,
  543.               params.appAreaTop,
  544.               MIN(kMaxApplicationWidth, params.appAreaWidth),
  545.               MIN(kMaxApplicationHeight, params.appAreaHeight)
  546.               );
  547.       end,
  548.     entryRoutingFrame:
  549.       {
  550.            zap:    {
  551.                   Title:    "Beam Datum",
  552.                   routeForm:    'zapSlip,
  553.                   },
  554.                   
  555.           separator: NIL,
  556.               
  557.           delete: {
  558.                   title: "Delete",
  559.                   routeScript: 'DeleteActionScript, 
  560.               },
  561.       
  562.           duplicate: {
  563.                   title: "Duplicate",
  564.                   routeScript: 'DuplicateActionScript,
  565.               },
  566.         
  567.           card: ROM_CardAction,
  568.       }
  569.    };
  570.  
  571. InfoLabel := /* child of GoodFormBase */
  572.    {text: "Status:",
  573.     viewBounds: {left: 5, top: 30, right: 90, bottom: 45},
  574.     _proto: protoStaticText,
  575.     debug: "InfoLabel"
  576.    };
  577.  
  578.  
  579.  
  580. infoField := /* child of GoodFormBase */
  581.    {
  582.     text:
  583.       "Tap the up and down arrows to scroll in the database.  Tap the \"New\" button to create a new record."
  584.     ,
  585.     viewBounds: {left: 0, top: 0, right: 220, bottom: 55},
  586.     viewFormat: 336,
  587.     viewJustify: 10368,
  588.     _proto: protoStaticText,
  589.     debug: "infoField"
  590.    };
  591. // View infoField is declared to GoodFormBase
  592.  
  593.  
  594.  
  595. ItemLabel := /* child of GoodFormBase */
  596.    {text: "Current Item:",
  597.     viewBounds: {left: 0, top: 12, right: 85, bottom: 27},
  598.     viewJustify: 8398976,
  599.     _proto: protoStaticText,
  600.     debug: "ItemLabel"
  601.    };
  602. // View ItemLabel is declared to GoodFormBase
  603.  
  604.  
  605.  
  606. inputField := /* child of GoodFormBase */
  607.    {viewFlags: 6657,
  608.     viewFormat: 12625,
  609.     viewlinespacing: 20,
  610.     viewFont: userFont18,
  611.     viewBounds: {left: 0, top: 0, right: 220, bottom: 102},
  612.     viewJustify: 10368,
  613.     viewChangedScript:
  614.       func(slot, view)
  615.       begin
  616.           :SetDirty(true);
  617.       end,
  618.     viewclass: 81,
  619.     debug: "inputField"
  620.    };
  621. // View inputField is declared to GoodFormBase
  622.  
  623.  
  624.  
  625. _view000 := /* child of GoodFormBase */ {_proto: protoStatus};
  626.  
  627. _view001 := /* child of _view000 */ {_proto: protoActionButton};
  628.  
  629.  
  630.  
  631. _view002 := /* child of _view000 */
  632.    {viewBounds: {left: -23, top: 2, right: -6, bottom: 15},
  633.     _proto: protoFilingButton
  634.    };
  635.  
  636.  
  637.  
  638. New := /* child of _view000 */
  639.    {text: "New",
  640.     buttonClickScript:
  641.       func()
  642.       begin
  643.        :SetTarget(:MakeNewEntry());
  644.       end,
  645.     viewBounds: {left: 28, top: 2, right: 54, bottom: 15},
  646.     viewJustify: 8388614,
  647.     _proto: protoTextButton,
  648.     debug: "New"
  649.    };
  650.  
  651. // After Script for "New"
  652. thisView := New;
  653. // set the bounds of the button so that it is to the right
  654. // of the clock and the correct height for the status bar
  655. thisView.viewBounds := ButtonBounds(-(thisView.viewBounds.right - thisView.viewBounds.left));
  656.  
  657.  
  658.  
  659.  
  660.  
  661. folderTab := /* child of GoodFormBase */
  662.    {_proto: protoFolderTab, debug: "folderTab"};
  663. // View folderTab is declared to GoodFormBase
  664.  
  665.  
  666.  
  667.  
  668.  
  669.  
  670.  
  671. // ---- Beginning of section for non used Layout files ----
  672.  
  673. // End of output